/*
#ifndef _ABSTRACTTYPE_CPP
#define _ABSTRACTTYPE_CPP
*/
#include "stdafx.h"
#include "AbstractType.h"
/*
#ifndef _TYPE_CPP
#include "Type.cpp"
#endif
  */
Token::pointer AbstractType::applyArgument(Token::const_reference To) const{
	if(To.isType())
		return getBody().replaceAll(getVar(), To);	
	throw Type::exception("Illegal Type combination at Token::pointer AbstractType::applyArgument(Token::const_reference To) const");
}

Token::pointer AbstractType::clone() const{
	  return new  AbstractType(*this);
}


string AbstractType::toString() const{
	if(hasSyntax( )) return SyntacticSugar;
	return string("(TT") + getVar().toString( )+string(".")+getBody().toString( )+ string(")");
	}

string AbstractType::view() const {
	return	string("(TT") + getVar().view()+"."+getBody().view()+")";
	}

bool AbstractType::operator==(Token::const_reference To) const {
	if(To.isType()){
		Type::const_reference Ty = _TYPE(To);
		if(Ty.isAbstractType()){
			const AbstractType& AT =  _ABSTRACTTYPE(Ty);
			BoundedTypeVariable RandomVar("X");
			Token::pointer LeftArgument = getBody().replaceAll(getVar(), RandomVar);
			Token::pointer RightArgument = AT.getBody().replaceAll(AT.getVar(), RandomVar);
			bool res = LeftArgument->operator==(*RightArgument);
			delete LeftArgument; 
			delete RightArgument;
			return res;
		}
	}
	return false;
}

Token::pointer AbstractType::replaceAll(Token::const_reference To1, Token::const_reference To2) const{		
	if(this->operator ==(To1))
		return To2.clone();

	Token::pointer NewBody = getBody().replaceAll(To1, To2);
	Token::pointer Res = new AbstractType(_TYPE(*NewBody), getVar());
	delete NewBody;
	return Res;
}

size_t AbstractType::complexity() const {
	return getVar().complexity() + getBody().complexity()+Type::complexity();
	}


Type::const_reference AbstractType::getBody() const{
	return *(static_cast<Type*>(this->VarBody.second));
}
Type::const_reference AbstractType::getVar() const{
	return *(static_cast<Type*>(this->VarBody.first));
}

AbstractType::AbstractType(const Type& Ty1, const  Type& Ty2, const string& ss):
Type(ss), VarBody(BoundedTypeVariable( ),Ty1){
	BoundedTypeVariable* TyVar = new BoundedTypeVariable("X");
	Token::pointer NewTy = Ty1.replaceAll(Ty2, *TyVar);
	this->VarBody = TokenPair(*TyVar, *NewTy);
    delete TyVar;
	delete NewTy;
}

AbstractType::AbstractType(const AbstractType& Ty):
Type(Ty),VarBody(Ty.VarBody){
}


AbstractType::~AbstractType(){
}

//#endif

